package com.globefrog.framework.juc.proxy;


import com.globefrog.framework.common.constant.LogConstants;
import com.globefrog.framework.common.enums.LogLevelEnum;
import com.globefrog.framework.log.LogHelper;
import com.globefrog.framework.log.handler.ErrorHandler;
import com.globefrog.framework.log.proxy.CallableExtra;
import com.globefrog.framework.log.proxy.LogProxyCallable;
import java.util.concurrent.Callable;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;

/**
 * callable 代理类进行日志初始化和call的调用.
 *
 * @author caijinbang
 * @date 2021-01-10 22:00
 */
@Slf4j
@EqualsAndHashCode(callSuper = true)
public class CallableProxy<T> extends LogProxyCallable<T> implements Comparable<CallableProxy<T>> {

  /**
   * 子任务名称.
   */
  private static final String SUB_TASK = "sub-task";
  /**
   * 日志帮助类.
   */
  private final LogHelper logHelper;

  /**
   * 错误处理.
   */
  private final ErrorHandler errorHandler;
  /**
   * 日志是否分开.
   */
  private final boolean logSeparate;

  /**
   * 构造函数.
   *
   * @param delegate     代理类
   * @param logHelper    日志帮助类
   * @param errorHandler 错误处理
   * @param logSeparate  日志是否分离
   */
  public CallableProxy(Callable<T> delegate, LogHelper logHelper, ErrorHandler errorHandler,
      boolean logSeparate) {
    // 父类初始化
    super(delegate);
    this.logHelper = logHelper;
    this.errorHandler = errorHandler;
    this.logSeparate = logSeparate;
  }

  /**
   * 执行日志初始化及call()的调用.
   *
   * @return 对象
   * @throws Exception 异常
   */
  @Override
  public T call() throws Exception {
    if (this.logSeparate) {
      MDC.put(LogConstants.MDC_BUSINESS_CONTEXT, getParentBusinessContext());
      String taskName = "sub-task";
      if (this.delegate instanceof CallableExtra) {
        taskName = ((CallableExtra) this.delegate).getName();
      }
      String action = getParentAction() + "-" + taskName;
      // 初始化日志
      logHelper.initLog(LogLevelEnum.ALL, this.getParentRequestId(), "", SUB_TASK, action);
    } else {
      // 如果日志需要分离,需要先清空MDC内容,重新put
      initLogMdc();
    }
    try {
      long currentThreadId = Thread.currentThread().getId();
      log.debug("start task, task={}, currentThread={}", delegate, currentThreadId);
      // 执行真正的call方法
      return delegate.call();
    } catch (Throwable throwable) {
      if (logSeparate) {
        errorHandler.handle(throwable);
      }
      throw throwable;
    } finally {
      long currentThreadId = Thread.currentThread().getId();
      log.debug("end task, task={}, currentThread={}", delegate, currentThreadId);
      if (logSeparate) {
        // 结束后保存actionLog和traceLog，并清除MDC数据
        logHelper.endLog(LogLevelEnum.ALL);
        MDC.clear();
      }
    }
  }

  /**
   * 比较代理对象是否同一个.
   *
   * @param o 代理对象
   * @return 比较结果
   */
  public int compareTo(CallableProxy<T> o) {
    if (this == o) {
      return 0;
    } else if (o == null) {
      return -1;
    } else {
      return this.delegate != null && o.delegate != null && this.delegate.getClass() == o.delegate
          .getClass() && this.delegate instanceof Comparable ? ((Comparable) this.delegate)
          .compareTo(o.delegate) : 0;
    }
  }
}
